/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

import {expect} from '@playwright/test';

import {moveLeft} from '../keyboardShortcuts/index.mjs';
import {
  assertHTML,
  assertSelection,
  click,
  dragImage,
  dragMouse,
  evaluate,
  focusEditor,
  html,
  initialize,
  insertSampleImage,
  insertUploadImage,
  insertUrlImage,
  IS_COLLAB_V2,
  IS_WINDOWS,
  LEGACY_EVENTS,
  SAMPLE_IMAGE_URL,
  SAMPLE_LANDSCAPE_IMAGE_URL,
  SAMPLE_SVG_URL,
  selectorBoundingBox,
  test,
  waitForSelector,
} from '../utils/index.mjs';

test.describe('Images', () => {
  // TODO(collab-v2): nested editors are not supported yet
  test.skip(IS_COLLAB_V2);

  test.beforeEach(({isCollab, page}) => initialize({isCollab, page}));
  test(`Can create a decorator and move selection around it`, async ({
    page,
    isPlainText,
    isCollab,
  }) => {
    test.skip(isPlainText);
    await focusEditor(page);

    await insertSampleImage(page);

    await waitForSelector(page, '.editor-image img');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 1,
      anchorPath: [0],
      focusOffset: 1,
      focusPath: [0],
    });

    await focusEditor(page);
    await page.keyboard.press('ArrowLeft');
    await page.keyboard.press('ArrowLeft');
    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });

    await page.keyboard.press('ArrowRight');
    await page.keyboard.press('ArrowRight');
    await assertSelection(page, {
      anchorOffset: 1,
      anchorPath: [0],
      focusOffset: 1,
      focusPath: [0],
    });

    await page.keyboard.press('ArrowRight');
    await page.keyboard.press('ArrowRight');
    await page.keyboard.press('Backspace');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto"><br /></p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });

    await insertSampleImage(page);

    await click(page, '.editor-image img');
    // The focus on the decorator doesn't seem to work in the right frame?
    if (!isCollab) {
      await assertHTML(
        page,
        html`
          <p class="PlaygroundEditorTheme__paragraph" dir="auto">
            <span
              class="editor-image"
              contenteditable="false"
              data-lexical-decorator="true">
              <div draggable="true">
                <img
                  class="focused draggable"
                  alt="Yellow flower in tilt shift lens"
                  draggable="false"
                  src="${SAMPLE_IMAGE_URL}"
                  style="height: inherit; max-width: 500px; width: inherit;" />
              </div>
              <div>
                <button class="image-caption-button">Add Caption</button>
                <div class="image-resizer image-resizer-n"></div>
                <div class="image-resizer image-resizer-ne"></div>
                <div class="image-resizer image-resizer-e"></div>
                <div class="image-resizer image-resizer-se"></div>
                <div class="image-resizer image-resizer-s"></div>
                <div class="image-resizer image-resizer-sw"></div>
                <div class="image-resizer image-resizer-w"></div>
                <div class="image-resizer image-resizer-nw"></div>
              </div>
            </span>
            <br />
          </p>
        `,
        true,
      );
    }

    await page.keyboard.press('Backspace');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto"><br /></p>
      `,
    );

    await click(page, 'div[contenteditable="true"]');

    await insertSampleImage(page);

    await waitForSelector(page, '.editor-image img');

    await focusEditor(page);

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 1,
      anchorPath: [0],
      focusOffset: 1,
      focusPath: [0],
    });

    await page.keyboard.press('ArrowLeft');
    await page.keyboard.press('ArrowLeft');

    await page.keyboard.press('Delete');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto"><br /></p>
      `,
    );

    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });
  });

  test('Can add images and delete them correctly', async ({
    page,
    isPlainText,
  }) => {
    test.skip(isPlainText);

    await focusEditor(page);

    await insertSampleImage(page);

    await insertSampleImage(page);

    await focusEditor(page);
    await moveLeft(page, 4);

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });

    await page.keyboard.press('Delete');
    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });

    await page.keyboard.press('Delete');
    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto"><br /></p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 0,
      anchorPath: [0],
      focusOffset: 0,
      focusPath: [0],
    });

    await page.keyboard.type('Test');
    await insertSampleImage(page);
    await insertSampleImage(page);

    await focusEditor(page);
    await moveLeft(page, 4);

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">Test</span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 4,
      anchorPath: [0, 0, 0],
      focusOffset: 4,
      focusPath: [0, 0, 0],
    });
    await page.keyboard.press('Delete');
    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">Test</span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
    await assertSelection(page, {
      anchorOffset: 4,
      anchorPath: [0, 0, 0],
      focusOffset: 4,
      focusPath: [0, 0, 0],
    });
  });

  test('Can add images by arbitrary URL', async ({
    page,
    isPlainText,
    isCollab,
  }) => {
    test.skip(isPlainText || isCollab, 'Skip in plain text and collab mode');

    await focusEditor(page);

    await insertUrlImage(page, SAMPLE_SVG_URL, 'lexical logo');

    await insertUploadImage(
      page,
      'packages/lexical-playground/src/images/yellow-flower-small.jpg',
      'a pretty yellow flower :)',
    );

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="lexical logo"
                draggable="false"
                src="${SAMPLE_SVG_URL}"
                style="height: 112px; max-width: 500px; width: 500px" />
            </div>
          </span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="a pretty yellow flower :)"
                draggable="false"
                src=""
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
  });

  test('Can be dragged and dropped correctly when the image is clicked', async ({
    page,
    isPlainText,
    browserName,
    isCollab,
  }) => {
    test.skip(isPlainText);
    test.skip(browserName === 'firefox' && isCollab);
    test.skip(browserName === 'firefox' && IS_WINDOWS);

    await focusEditor(page);

    await page.keyboard.type('HelloWorld');
    await page.keyboard.press('Enter');

    await insertSampleImage(page);

    await click(page, '.editor-image img');

    // When actually using firefox, we can drag the image to the middle of the text,
    // but when running the playwright test, we can't get the correct values from `event.rangeParent` and `event.rangeOffset`,
    // so for now we can only test the case of dragging the image to the end of the text
    if (browserName === 'firefox') {
      await dragImage(page, 'span[data-lexical-text="true"]', 'middle', 'end');

      await waitForSelector(page, '.editor-image img');

      await click(
        page,
        'div.ContentEditable__root > p:first-of-type > span:first-of-type',
      );

      await assertHTML(
        page,
        html`
          <p class="PlaygroundEditorTheme__paragraph" dir="auto">
            <span data-lexical-text="true">HelloWorld</span>
            <span
              class="editor-image"
              contenteditable="false"
              data-lexical-decorator="true">
              <div draggable="false">
                <img
                  alt="Yellow flower in tilt shift lens"
                  draggable="false"
                  src="${SAMPLE_IMAGE_URL}"
                  style="height: inherit; max-width: 500px; width: inherit" />
              </div>
            </span>
            <br />
          </p>
          <p class="PlaygroundEditorTheme__paragraph" dir="auto">
            <br />
          </p>
        `,
      );
    } else {
      await dragImage(page, 'span[data-lexical-text="true"]');

      await waitForSelector(page, '.editor-image img');

      await click(
        page,
        'div.ContentEditable__root > p:first-of-type > span:first-of-type',
      );

      await assertHTML(
        page,
        html`
          <p class="PlaygroundEditorTheme__paragraph" dir="auto">
            <span data-lexical-text="true">Hello</span>
            <span
              class="editor-image"
              contenteditable="false"
              data-lexical-decorator="true">
              <div draggable="false">
                <img
                  alt="Yellow flower in tilt shift lens"
                  draggable="false"
                  src="${SAMPLE_IMAGE_URL}"
                  style="height: inherit; max-width: 500px; width: inherit" />
              </div>
            </span>
            <span data-lexical-text="true">World</span>
          </p>
          <p class="PlaygroundEditorTheme__paragraph" dir="auto">
            <br />
          </p>
        `,
      );
    }
  });

  test('Cannot be dragged without being clicked', async ({
    page,
    isPlainText,
  }) => {
    test.skip(isPlainText);

    await focusEditor(page);

    await page.keyboard.type('HelloWorld');
    await page.keyboard.press('Enter');

    await insertSampleImage(page);

    await dragImage(page, 'span[data-lexical-text="true"]');

    await waitForSelector(page, '.editor-image img');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">HelloWorld</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
  });

  test('Select image, then select text - EditorState._selection updates with mousedown #2901', async ({
    page,
    isPlainText,
    browserName,
    isCollab,
  }) => {
    // This test is flaky in collab #3915
    test.fixme(isCollab);
    test.skip(isPlainText);

    await page.setViewportSize({
      height: 1000,
      width: 2000,
    });

    await focusEditor(page);

    await page.keyboard.type('HelloWorld');
    await page.keyboard.press('Enter');
    await insertSampleImage(page);
    await click(page, '.editor-image img');

    const textBoundingBox = await selectorBoundingBox(
      page,
      'span[data-lexical-text="true"]',
    );
    await dragMouse(page, textBoundingBox, textBoundingBox, {
      positionEnd: 'middle',
      positionStart: 'start',
    });

    const lexicalSelection = await evaluate(page, (editor) => {
      return window.lexicalEditor._editorState._selection;
    });
    expect(lexicalSelection.anchor).toBeTruthy();
    expect(lexicalSelection.focus).toBeTruthy();
  });

  test('Node selection: can select multiple image nodes and replace them with a new image', async ({
    page,
    isPlainText,
    browserName,
  }) => {
    // It doesn't work in legacy events mode in WebKit #5673
    test.fixme(LEGACY_EVENTS && browserName === 'webkit');
    test.skip(isPlainText);

    await focusEditor(page);

    await page.keyboard.type('text1');
    await page.keyboard.press('Enter');
    await insertSampleImage(page);
    await page.keyboard.press('Enter');
    await page.keyboard.type('text2');
    await page.keyboard.press('Enter');
    await insertSampleImage(page, 'alt');
    await page.keyboard.press('Enter');
    await page.keyboard.type('text3');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text1</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit" />
            </div>
          </span>
          <br />
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text2</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Daylight fir trees forest glacier green high ice landscape"
                draggable="false"
                src="${SAMPLE_LANDSCAPE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit" />
            </div>
          </span>
          <br />
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text3</span>
        </p>
      `,
    );

    await click(
      page,
      '.editor-image img[alt="Yellow flower in tilt shift lens"]',
    );
    await page.keyboard.down('Shift');
    await click(
      page,
      '.editor-image img[alt="Daylight fir trees forest glacier green high ice landscape"]',
    );
    await page.keyboard.up('Shift');

    await insertSampleImage(page);
    await page.keyboard.type(' <- it works!');

    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text1</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto"><br /></p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text2</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit" />
            </div>
          </span>
          <span data-lexical-text="true">&lt;- it works!</span>
        </p>
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">text3</span>
        </p>
      `,
    );
  });

  test('Can resolve selection correctly when the image is clicked and dragged right', async ({
    page,
    isPlainText,
    browserName,
    isCollab,
  }) => {
    test.skip(isPlainText);
    let leftFrame = page;
    if (isCollab) {
      leftFrame = await page.frame('left');
    }
    await focusEditor(page);

    await page.keyboard.type('HelloWorld');
    await insertSampleImage(page);
    await click(page, '.editor-image img');

    await leftFrame.locator('.editor-image img').hover();
    await page.mouse.down();
    await leftFrame.locator('.PlaygroundEditorTheme__paragraph').hover();
    await page.mouse.up();
    await waitForSelector(page, '.editor-image img');
    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span data-lexical-text="true">HelloWorld</span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="Yellow flower in tilt shift lens"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
  });

  test(`Verifies image dimensions are properly calculated for both SVG and JPG formats`, async ({
    page,
    isPlainText,
    isCollab,
  }) => {
    test.skip(isPlainText || isCollab, 'Skip in plain text and collab mode');

    await focusEditor(page);

    // Insert an SVG image using the Lexical logo
    await insertUrlImage(page, SAMPLE_SVG_URL, 'lexical logo');

    // Insert a JPG image
    await insertUrlImage(page, SAMPLE_IMAGE_URL, 'sample image');

    // Verify both images are inserted with proper dimensions and styling
    await assertHTML(
      page,
      html`
        <p class="PlaygroundEditorTheme__paragraph" dir="auto">
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="lexical logo"
                draggable="false"
                src="${SAMPLE_SVG_URL}"
                style="height: 112px; max-width: 500px; width: 500px" />
            </div>
          </span>
          <span
            class="editor-image"
            contenteditable="false"
            data-lexical-decorator="true">
            <div draggable="false">
              <img
                alt="sample image"
                draggable="false"
                src="${SAMPLE_IMAGE_URL}"
                style="height: inherit; max-width: 500px; width: inherit;" />
            </div>
          </span>
          <br />
        </p>
      `,
    );
  });
});
